package org.steven.crm.app.api;

import com.steven.common.utils.StringUtil;
import com.steven.xdb.dbmanager.DBManager;
import com.steven.xdb.session.DBSession;
import com.steven.xdb.session.DBSessionHolder;
import org.apache.log4j.Logger;
import org.steven.crm.core.service.area.AreaService;
import org.steven.crm.core.service.dict.DictService;
import org.steven.crm.core.service.system.SystemConfigService;
import org.steven.crm.core.service.user.UserService;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class LocalDataCache {
	private static Logger logger = Logger.getLogger(LocalDataCache.class);

	private static final SystemConfigService systemConfigService = new SystemConfigService();
	private final static DictService dictService = new DictService();

	private static final AreaService areaService = new AreaService();

	private static final UserService userService = new UserService();

	private static LocalDataCache instance = new LocalDataCache();

	private Map<String, Object> dict;

	private Map<String, List<Map<String, String>>> tableDatas;
	private Map<String, Map<String, Map<String, String>>> tableDataHash;

	private List<Map<String, String>> provinces;
	private List<Map<String, String>> citys;
	private List<Map<String, String>> towns;
	private Map<String, Map<String, String>> provinceHash;

	private Map<String, List<Map<String, String>>> provinceCitys;
	private Map<String, Map<String, String>> cityHash;

	private Map<String, List<Map<String, String>>> cityTowns;
	private Map<String, Map<String, String>> townHash;

	private List<Map<String, Object>> areaTree;
	
	private Map<String, String> systemConfigMap;

	private List<Map<String, String>> countryCodes;
	
	private LocalDataCache() {
	}
	
	public static LocalDataCache getInstance() {
		return instance;
	}
	
	public synchronized void loadData() {
		try {
			reloadSystemConfig();

			reloadDict();

			reloadArea();

		} catch (Exception e) {
			e.printStackTrace();
			logger.error("Datacache reload error", e);
		} finally {
			DBSession.close(DBSessionHolder.get());
		}
	}
	

	public void reloadSystemConfig() throws Exception {
		systemConfigMap = systemConfigService.readAll();
		AppKeys.setSysConfig(systemConfigMap);
	}

	public void reloadDict() throws Exception {
		dict = dictService.readAll();
	}

	private void reloadArea() throws Exception {
		provinces = areaService.readProvinces();
		provinceHash = new HashMap<>();
		provinceCitys = new HashMap<>();
		for (int i = 0; i < provinces.size(); i++) {
			provinceHash.put(provinces.get(i).get("id"), provinces.get(i));
			provinceCitys.put(provinces.get(i).get("id"), new ArrayList<>());
		}

		cityHash = new HashMap<>();
		cityTowns = new HashMap<>();
		citys = areaService.readCitys();
		for (int i = 0; i < citys.size(); i++) {
			Map<String, String> city = citys.get(i);
			cityHash.put(city.get("id"), city);
			List<Map<String, String>> datas = provinceCitys.get(city.get("pid"));
			if (datas != null) {
				datas.add(city);
			}
			cityTowns.put(city.get("id"), new ArrayList<>());
		}

		townHash = new HashMap<>();
		towns = areaService.readTowns();
		for (int i = 0; i < towns.size(); i++) {
			Map<String, String> town = towns.get(i);
			townHash.put(town.get("id"), town);
			List<Map<String, String>> datas = cityTowns.get(town.get("pid"));
			if (datas != null) {
				datas.add(town);
			}
		}

		areaTree = areaService.makeTree(3);
	}

	public void loadTableData(DBSession session, String tableName) throws Exception {
		List<Map<String, String>> datas = new ArrayList<>();
		String orderSql = "";
		Map<String, String> k = new HashMap<>();
		if ("city".equals(tableName)) {
			k.put("validFlag", "1");
			k.put("deleted", "0");
		}
		datas = DBManager.query(session, tableName, "*", k, orderSql);
		
		Map<String, Map<String, String>> datasHash = new HashMap<String, Map<String,String>>();
		Map<String, String> tmpData;
		for (int i = 0; i < datas.size(); ++i) {
			tmpData = datas.get(i);
			datasHash.put(tmpData.get(tableName + "ID"), tmpData);
		}
		tableDatas.put(tableName, datas);
		tableDataHash.put(tableName, datasHash);
	}
	
	public List<Map<String, String>> getTableDatas(String tableName) {
		return tableDatas.get(tableName);
	}
	
	public Map<String, Map<String, String>> getTableDatasHash(String tableName) {
		return tableDataHash.get(tableName);
	}
	
	public Map<String, String> getTableDataByID(String tableName, String id) {
		Map<String, String> data = getTableDatasHash(tableName).get(id);
		if (data == null) {
			return new HashMap<>();
		}
		return data;
	}
	
	public String getTableDataColumnValue(String tableName, String id, String column) {
		Map<String, String> data = getTableDataByID(tableName, id);
		return data.get(column) == null ? "" : data.get(column);
	}
	
	public String getTableDataColumnsValue(String tableName, String ids, String column) {
		String[] id = StringUtil.split(ids, ", ");
		StringBuffer sbf = new StringBuffer();
		int index = 0;
		for (int i = 0; i < id.length; ++i) {
			Map<String, String> data = getTableDataByID(tableName, id[i]);
			String tmpColumnValue = data.get(column) == null ? "" : data.get(column);
			if (!tmpColumnValue.equals("")) {
				if (index != 0) {
					sbf.append(",").append(tmpColumnValue);
				} else {
					sbf.append(tmpColumnValue);
				}
				index++;
			}
		}
		
		return sbf.toString();
	}

	public String getSystemConfig(String key) {
		return systemConfigMap.get(key) == null
			? "" : systemConfigMap.get(key);
	}

	public List<Map<String, String>> getDictDatas(String dictCode) {
		List<Map<String, String>> dictValues = (List<Map<String, String>>) dict.get(dictCode);
		return null == dictValues ? new ArrayList<>() : dictValues;
	}

	public Map<String, String> getDictValueByCode(String dictCode, String dictValueCode) {
		List<Map<String, String>> dictValues = getDictDatas(dictCode);
		for (Map<String, String> dictValue : dictValues) {
			if (dictValue.get("code").equals(dictValueCode)) {
				return dictValue;
			}
		}

		return new HashMap<>();
	}

	public String getDictValueNameByCode(String dictCode, String dictValueCode) {
		Map<String, String> data = getDictValueByCode(dictCode, dictValueCode);
		return data.get("name") == null ? "" : data.get("name");
	}

	public String getDictValueNamesByCode(String dictCode, String dictValueCodes) {
		String[] codes = StringUtil.split(dictValueCodes, ", ");
		StringBuffer sbf = new StringBuffer();
		int index = 0;
		for (int i = 0; i < codes.length; ++i) {
			Map<String, String> data = getDictValueByCode(dictCode, codes[i]);
			String tmpName = getDictValueNameByCode(dictCode, codes[i]);
			tmpName = null == tmpName ? "" : tmpName;
			if (!tmpName.equals("")) {
				if (index != 0) {
					sbf.append(",").append(tmpName);
				} else {
					sbf.append(tmpName);
				}
				index++;
			}
		}

		return sbf.toString();
	}

	public Map<String, String> getProvince(String id) {
		return provinceHash.get(id) == null ? new HashMap<>() : provinceHash.get(id);
	}

	public Map<String, String> getCity(String id) {
		return cityHash.get(id) == null ? new HashMap<>() : cityHash.get(id);
	}

	public Map<String, String> getTown(String id) {
		return townHash.get(id) == null ? new HashMap<>() : townHash.get(id);
	}
	public List<Map<String, String>> getProvinces() {
		return provinces;
	}

	public List<Map<String, String>> getCitiesByProvinceId(String provinceId) {
		List<Map<String, String>> datas = provinceCitys.get(provinceId);
		if (datas == null) {
			datas = new ArrayList<>();
		}
		return datas;
	}

	public List<Map<String, String>> getTownsByCityId(String cityId) {
		List<Map<String, String>> datas = cityTowns.get(cityId);
		if (datas == null) {
			datas = new ArrayList<>();
		}
		return datas;
	}

	public List<Map<String, Object>> getAreaTree() {
		return areaTree;
	}

	public List<Map<String, String>> getCountryCodes() {
		return countryCodes;
	}
}
